package util;

import controller.SessionController;
import java.lang.reflect.Field;
import java.net.InetAddress;
import java.net.UnknownHostException;
import javax.faces.application.FacesMessage;
import javax.faces.component.UIComponent;
import javax.faces.component.html.HtmlOutputLabel;
import javax.faces.context.FacesContext;
import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import model.Usuario;
import org.primefaces.context.RequestContext;

/**
 * Biblioteca de controle e manipulação de componentes da página (Faces).
 *
 * @author Rodolpho
 */
public abstract class FacesUtil {

    /**
     * Retorna o diretório real do servidor
     *
     * @param String diretorio
     * @return String diretorioReal
     */
    public static String getDiretorioReal(String diretorio) {
        ServletContext scontext = (ServletContext) FacesContext.getCurrentInstance().getExternalContext().getContext();
        return scontext.getRealPath(diretorio);
    }

    /**
     * Obtém o nome da página atual.
     *
     * @return String
     */
    public static String getPaginaAtual() {
        return FacesContext.getCurrentInstance().getViewRoot().getViewId();
    }

    /**
     * Redireciona para a página passada por parâmetro
     *
     * @param pagina
     */
    public static void redirecionarPagina(String pagina) throws CustomException {
        try {
            FacesContext.getCurrentInstance().getExternalContext().redirect(pagina);
        } catch (Exception e) {
            throw new CustomException("Falha ao redirecionar para a página: " + pagina, e);
        }
    }

    /**
     * Obtém o nome da página pai.
     *
     * @return String
     */
    public static String getPaginaPai() {
        String[] url = FacesContext.getCurrentInstance().getViewRoot().getViewId().split("/");
        return url[url.length - 1].replace(".xhtml", "");
    }

    /**
     * Obtém o objeto managed Bean passado por parâmetro.
     *
     * @return String
     */
    public static Object getManagedBean(Class controller) {
        String controllerName = ((javax.faces.bean.ManagedBean) controller.getAnnotation(javax.faces.bean.ManagedBean.class)).name();
        return FacesContext.getCurrentInstance().getExternalContext().getSessionMap().get(controllerName);
    }

    /**
     * Retorna o usuário logado na sessão.
     *
     * @return Usuario
     */
    public static Usuario getUsuarioLogado() {
        return ((SessionController) getManagedBean(SessionController.class)).getUsuarioLogado();
    }

    /**
     * Abre o dialog passado como parâmetro.
     *
     * @param dialogWidgetVar
     */
    public static void dialogAbrir(String dialogWidgetVar) {
        RequestContext.getCurrentInstance().execute(dialogWidgetVar + ".show();");
    }

    /**
     *
     * Executa o comando ALERT do JavaScript (Utilizado para DEBUG)
     *
     */
    public static void jsAlert(String msg) {
        RequestContext.getCurrentInstance().execute("alert('" + msg + "')");
    }

    /**
     *
     * Executa um comando Javascript.
     *
     * @param String;
     * @return void;
     *
     */
    public static void jsExecute(String function) {
        RequestContext.getCurrentInstance().execute(function);
    }

    /**
     * Fecha o dialog passado como parâmetro.
     *
     * @param dialogWidgetVar
     */
    public static void dialogFechar(String dialogWidgetVar) {
        RequestContext.getCurrentInstance().execute(dialogWidgetVar + ".hide();");
    }

    /**
     * Atualiza componente da view passado como id como parâmetro.
     *
     * @param idComponente
     */
    public static void atualizarComponente(String idComponente) {
        RequestContext.getCurrentInstance().update(idComponente);
    }

    /**
     * Inicia a progressBar passada como parâmetro
     *
     * @param progressBarWidgetVar
     */
    public static void progressBarStart(String progressBarWidgetVar) {
        RequestContext.getCurrentInstance().execute(progressBarWidgetVar + ".start();");
    }

    /**
     * Habilita o commandButton passado como parâmetro
     *
     * @param commandButtonWidgetVar
     */
    public static void commandButtonEnable(String commandButtonWidgetVar) {
        RequestContext.getCurrentInstance().execute(commandButtonWidgetVar + ".enable();");
    }

    /**
     * Desabilita o commandButton passado como parâmetro
     *
     * @param commandButtonWidgetVar
     */
    public static void commandButtonDisable(String commandButtonWidgetVar) {
        RequestContext.getCurrentInstance().execute(commandButtonWidgetVar + ".disable();");
    }

    public static String getRequestParameterMap(String param) {
        return FacesContext.getCurrentInstance().getExternalContext().getRequestParameterMap().get(param);
    }

    /**
     * Exibe mensagem informativa com o texto passado por parâmetro.
     *
     * @param actionEvent
     * @param titulo
     * @param mensagem
     */
    public static void exibirMsgInfo(String idComponent, String titulo, String mensagem) {
        FacesContext.getCurrentInstance().addMessage(idComponent, new FacesMessage(FacesMessage.SEVERITY_INFO, titulo, mensagem));
    }

    /**
     * Exibe mensagem de alerta com o texto passado por parâmetro.
     *
     * @param actionEvent
     * @param titulo
     * @param mensagem
     */
    public static void exibirMsgWarn(String idComponent, String titulo, String mensagem) {
        FacesContext.getCurrentInstance().addMessage(idComponent, new FacesMessage(FacesMessage.SEVERITY_WARN, titulo, mensagem));
    }

    /**
     * Exibe mensagem de erro com o texto passado por parâmetro.
     *
     * @param actionEvent
     * @param titulo
     * @param mensagem
     */
    public static void exibirMsgError(String idComponent, String titulo, String mensagem) {
        FacesContext.getCurrentInstance().addMessage(idComponent, new FacesMessage(FacesMessage.SEVERITY_ERROR, titulo, mensagem));
    }

    /**
     * Exibe mensagem de erro fatal com o texto passado por parâmetro.
     *
     * @param actionEvent
     * @param titulo
     * @param mensagem
     */
    public static void exibirMsgFatal(String idComponent, String titulo, String mensagem) {
        FacesContext.getCurrentInstance().addMessage(idComponent, new FacesMessage(FacesMessage.SEVERITY_FATAL, titulo, mensagem));
    }

    /**
     * Exibe o dialog contendo as informações da exceção passada por parâmetro.
     *
     * @param e
     */
    public static void exibirMsgExcecao(CustomException e) {
        LibUtil.printMsgExcecao(e);

        String erroId = LibUtil.nvl(e.getErroId(), "--");
        String erroDescricao = LibUtil.nvl(e.getErroDescricao(), "--");
        String erroMsgOriginal = LibUtil.nvl(e.getErroMsgOriginal(), "--");

        ((HtmlOutputLabel) FacesContext.getCurrentInstance().getViewRoot().findComponent("frmExcecao").findComponent("txtErroId")).setValue(erroId);
        ((HtmlOutputLabel) FacesContext.getCurrentInstance().getViewRoot().findComponent("frmExcecao").findComponent("txtErroDescricao")).setValue(erroDescricao);
        ((HtmlOutputLabel) FacesContext.getCurrentInstance().getViewRoot().findComponent("frmExcecao").findComponent("txtErroMsgOriginal")).setValue(erroMsgOriginal);

        jsExecute("showException();");
    }

    /**
     * Retorna o objeto.
     *
     * @param component
     * @param value
     * @return String
     */
    public static Object getObject(UIComponent component, String value) throws CustomException {
        if (value != null) {
            try {
                Object map = component.getAttributes().get(value);
                return map;
            } catch (Exception e) {
                throw new CustomException("Falha ao obter o objeto " + value, e);
            }
        }
        return null;
    }

    /**
     * Retorna o objeto convertido em String.
     *
     * @param ctx
     * @param component
     * @param value
     * @return String
     */
    public static String getObjectAsString(FacesContext ctx, UIComponent component, Object obj) throws CustomException {

        if (obj != null && !"".equals(obj)) {
            String id = null;
            try {
                Class clazz = component.getValueExpression("value").getType(ctx.getELContext());
                Field idField = LibUtil.getId(clazz);
                if (idField.get(clazz.cast(obj)) != null) {
                    Object objClazz = clazz.cast(obj);
                    Object objcast = idField.get(objClazz);
                    id = objcast.toString();
                }

                if (id == null) {
                    id = "";
                }

                id = id.trim();
                component.getAttributes().put(id, component.getValueExpression("value").getType(ctx.getELContext()).cast(obj));
                return id;
            } catch (CustomException e) {
                throw e;
            } catch (Exception e) {
                throw new CustomException("Falha ao converter o objeto/entidade " + obj.getClass().getSimpleName() + ".", e);
            }
        }

        return null;
    }

    public static String selectOneMenuTitulo(String itens, int inicio, int selecionado) {
        String[] registros = itens.split(",");
        return registros[(selecionado - inicio)];
    }

    public static void abrirArquivo(String nome, byte[] arquivo) throws CustomException {
        try {
            HttpServletResponse res = (HttpServletResponse) FacesContext.getCurrentInstance().getExternalContext().getResponse();

            // Obtendo a extensão
            String[] aux = nome.split("\\.");
            String ext = aux[aux.length - 1];

            switch (ext) {
                case "jpg":
                case "jpeg":
                    res.setContentType("image/jpeg");
                case "gif":
                case "png":
                case "bmp":
                    res.setContentType("image/" + ext);
                    break;
                case "pdf":
                    res.setContentType("application/pdf");
                    break;
            }

            res.setHeader("Content-disposition", "inline;filename=" + nome);
            res.getOutputStream().write(arquivo);
            res.getCharacterEncoding();
            FacesContext.getCurrentInstance().responseComplete();
        } catch (Exception e) {
            throw new CustomException("Falha ao abrir o arquivo.", e);
        }
    }

    /**
     * Retorna o IP do client.
     *
     * @return String
     */
    public static String getIpClient() {
        HttpServletRequest request = (HttpServletRequest) FacesContext.getCurrentInstance().getExternalContext().getRequest();
        return request.getRemoteAddr();
    }

    /**
     * Retorna o nome da máquina do client.
     *
     * @return String
     */
    public static String getNomeMaquinaClient() throws CustomException {
        String nomeMaquina;
        try {
            nomeMaquina = InetAddress.getByName(getIpClient()).getHostName();
        } catch (UnknownHostException e) {
            throw new CustomException("Falha ao obter o nome da máquina", e);
        }
        return nomeMaquina;
    }
}
